package git.soulbgm.controller;

import git.soulbgm.common.constant.RedisKeyConstant;
import git.soulbgm.common.pojo.ResultData;
import git.soulbgm.common.pojo.ReturnCode;
import git.soulbgm.config.TokenConfig;
import git.soulbgm.pojo.PrincipalUser;
import git.soulbgm.utils.JsonUtil;
import git.soulbgm.utils.JwtUtil;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author SoulBGM
 * @version 1.0
 * @date 2019/10/31 15:47
 */
@RestController
public class TokenController {

    @Autowired
    private TokenConfig config;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @ApiOperation("获得Token")
    @RequestMapping(path = "token", method = RequestMethod.POST)
    public ResultData token(@RequestParam String username, @RequestParam String password, HttpServletResponse response) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
        ReturnCode code = null;
        try {
            subject.login(usernamePasswordToken);
        } catch (UnknownAccountException uae) {
            // 未知账户
            code = ReturnCode.UNKNOWN_ACCOUNT;
        } catch (IncorrectCredentialsException ice) {
            // 密码不正确
            code = ReturnCode.USERNAME_OR_PASSWORD_IS_INCORRECT;
        } catch (LockedAccountException lae) {
            // 账户已锁定
            code = ReturnCode.ACCOUNT_LOCKED;
        } catch (ExcessiveAttemptsException eae) {
            // 用户名或密码错误次数过多
            code = ReturnCode.TOO_MANY_INCORRECT_USERNAME_OR_PASSWORD;
        } catch (AuthenticationException e) {
            // 用户名或密码不正确
            code = ReturnCode.USERNAME_OR_PASSWORD_IS_INCORRECT;
        }
        if (!subject.isAuthenticated()) {
            // 登录失败
            usernamePasswordToken.clear();
            code = code != null ? code : ReturnCode.LOGIN_FAIL;
        } else {
            String token = onLoginSuccess((PrincipalUser) subject.getPrincipal());
            response.setHeader(config.getHeaderName(), token);
            return ResultData.getResultData(ReturnCode.LOGIN_SUCCESS, token);
        }
        return ResultData.getResultData(code);
    }

    @ApiOperation("注销")
    @RequestMapping(path = "logout2", method = RequestMethod.POST)
    public ResultData logout(HttpServletRequest request) {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            PrincipalUser user = (PrincipalUser) subject.getPrincipal();
            redisTemplate.delete(RedisKeyConstant.TOKEN + user.getId());
            subject.logout();
            return ResultData.getResultData(ReturnCode.LOGOUT_SUCCESS);
        } else {
            return ResultData.getResultData(ReturnCode.UNKNOWN_ACCOUNT);
        }
    }

    /**
     * 登录成功之后
     *
     * @param user 用户信息
     * @return token
     */
    private String onLoginSuccess(PrincipalUser user) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", user.getId());
        map.put("username", user.getUsername());
        redisTemplate.opsForValue().set(RedisKeyConstant.TOKEN + user.getId(), JsonUtil.toJson(user), config.getRefreshTokenExpireTime(), TimeUnit.MINUTES);
        return JwtUtil.buildJwt(map, config.getTokenExpireTime() * 60);
    }

}
